﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace Anonym.Common
{
    public static class Extends
    {
        /// <summary>
        /// 获取客户Ip
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public static string GetClientIp(this HttpContext context)
        {
            var userHostAddress = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(userHostAddress))
            {
                userHostAddress = context.Connection.RemoteIpAddress.ToString();
            }

            //最后判断获取是否成功，并检查IP地址的格式（检查其格式非常重要）
            if (!string.IsNullOrEmpty(userHostAddress) && Verify.IsIP(userHostAddress))
            {
                return userHostAddress;
            }
            return "127.0.0.1";
        }

        public static void SetObject(this ISession session, string key, object value)
        {
            session.SetString(key, JsonConvert.SerializeObject(value));
        }

        public static T GetObject<T>(this ISession session, string key)
        {
            var sessionData = session.GetString(key);
            return sessionData == null ? default(T) : JsonConvert.DeserializeObject<T>(sessionData);
        }

        /// <summary>
        /// object转json
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static string ToJson(this object obj)
        {
            return JsonConvert.SerializeObject(obj);
        }

        /// <summary>
        /// json字符串转object
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="str"></param>
        /// <returns></returns>
        public static T ToObject<T>(this string str)
        {
            return (str == null || str == "") ? default(T) : JsonConvert.DeserializeObject<T>(str);
        }

        public static T ToObjectPart<T>(this string str, string field)
        {
            List<string> l = field.Split(',').ToList();

            Dictionary<string, object> dic = str.ToObject<Dictionary<string, object>>();
            foreach (var item in dic)
            {
                if (l.Where(w => w.ToLower() == item.Key.ToLower()).Count() <= 0)
                    dic.Remove(item.Key);
            }
            return ToObject<T>(dic.ToJson());


            //T obj = str.ToObject<T>();
            //Type objType = obj.GetType();
            //PropertyInfo[] propertys = objType.GetProperties();
            //foreach (PropertyInfo pi in propertys)
            //{
            //    if (pi.PropertyType.IsPublic
            //        && pi.CanWrite
            //        && l.Where(w => w.ToLower() == pi.Name.ToLower()).Count() <= 0)
            //    {

            //        if (pi.PropertyType.Name.ToLower() == "string")
            //            pi.SetValue(obj, Convert.ChangeType("", pi.PropertyType), null);
            //        else
            //            //var v = Activator.CreateInstance(pi.PropertyType.v);

            //            pi.SetValue(obj, Activator.CreateInstance(pi.PropertyType), null);
            //        //pi.SetValue(obj, "");
            //    }
            //}
            //return obj;
        }

        /// <summary>
        /// 保留传入的key，其余的删除。不区分大小写
        /// </summary>
        /// <param name="dic"></param>
        /// <param name="field"></param>
        /// <returns></returns>
        public static void RetainPart(this Dictionary<string, string> dic, string field)
        {
            if (field == "") return;
            //List<string> l = field.Split(',').ToList();
            foreach (var item in dic)
            {
                if (!$",{field.ToLower()},".Contains($",{item.Key.ToLower()},"))
                    dic.Remove(item.Key);
            }
            //return;
        }

        /// <summary>
        /// 字典值填充模型
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="dic"></param>
        /// <param name="noField">需要排除的填充项，多个用逗号隔开</param>
        public static void DictionaryFill(this object obj, Dictionary<string, string> dic, string noField = "")
        {
            try
            {
                Type objType = obj.GetType();
                BindingFlags flag = BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.SetProperty;
                foreach (var item in dic)
                {
                    if (noField != "" && $",{noField.ToLower()},".Contains($",{item.Key.ToLower()},"))
                        continue;
                    else
                    {
                        var val = Convert.ChangeType(item.Value, objType.GetProperty(item.Key, flag).PropertyType);
                        objType.GetProperty(item.Key, flag).SetValue(obj, val, null);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception(obj.GetType().Name + "模型填充失败，检查传入的值是否正确");
            }
        }

        public static Dictionary<string, string> ToDictionary(this Enum em)
        {
            Dictionary<string, string> dic = new Dictionary<string, string>();
            foreach (int myCode in Enum.GetValues(em.GetType()))
            {
                string strName = Enum.GetName(em.GetType(), myCode);//获取名称
                string strVaule = myCode.ToString();//获取值
                dic.Add(strName, strVaule);
            }
            return dic;
        }

        /// <summary>
        /// 获取最小时间
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static DateTime GetMinTime(this DateTime t)
        {
            return new DateTime(1900, 1, 1);
        }

        /// <summary>
        /// 时间转换字符串
        /// </summary>
        /// <param name="t"></param>
        /// <param name="showMinute">是否显示小时分秒，默认显示。true显示，false不显示</param>
        /// <returns></returns>
        public static string ToDateString(this DateTime t, bool showMinute = true)
        {
            if ((t.Year == 1900 && t.Month == 1 && t.Day == 1) || t == DateTime.MinValue)
                return "";
            else
            {
                if (showMinute)
                    return t.ToString("yyyy-MM-dd HH:mm:ss");
                else
                    return t.ToString("yyyy-MM-dd");
            }
        }

        public static string ToMd532(this string str)
        {
            if (string.IsNullOrEmpty(str))
                throw new ArgumentNullException("对象为空");

            string pwd = "";
            MD5 md5 = System.Security.Cryptography.MD5.Create();//实例化一个md5对像

            // 加密后是一个字节类型的数组，这里要注意编码UTF8/Unicode等的选择　
            byte[] s = md5.ComputeHash(Encoding.UTF8.GetBytes(str));

            // 通过使用循环，将字节类型的数组转换为字符串，此字符串是常规字符格式化所得
            for (int i = 0; i < s.Length; i++)
            {
                // 将得到的字符串使用十六进制类型格式。格式后的字符是小写的字母，如果使用大写（X）则格式后的字符是大写字符 
                pwd = pwd + s[i].ToString("X2");
            }
            return pwd;
        }

        /// <summary>
        /// 检查传入的字段是否为空，只检查string类型。传入参数不区分大小写。
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="fields">格式说明："name 登录名,RealName 姓名"</param>
        /// <returns></returns>
        public static string VerifyEmpty(this object obj, string fields)
        {
            BindingFlags flag = BindingFlags.Public | BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.SetProperty;
            string errorMsg = "";
            string[] arr = fields.Split(',');
            try
            {
                foreach (string i in arr)
                {
                    var t = obj.GetType().GetProperty(i.Split(' ')[0], flag);
                    if (t.PropertyType.Name.ToLower() != "string")
                        continue;
                    if ((t.GetValue(obj) + "").Trim() == "")
                        errorMsg += i.Split(' ')[1] + ",";
                }
                if (errorMsg != "")
                    errorMsg += "必须填写！";
            }
            catch (Exception ex)
            {
                throw new Exception(obj.GetType().Name + "必填项目检查出错，检查传入的值是否正确");
            }
            return errorMsg;
        }

        /// <summary>
        /// 验证是否是手机号
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        public static bool VerifyPhone(this string s)
        {
            string mobileRegex = @"^1[1-9][0-9]{9}$";
            return Regex.IsMatch(s, mobileRegex);
        }

        #region 字典转换强类型
        /// <summary>
        /// 获取字典里的string类型值
        /// </summary>
        /// <param name="dic">字典</param>
        /// <param name="key">key</param>
        /// <param name="isNull">key的值是否可空，默认不能</param>
        /// <returns></returns>
        public static string GetDicByString(this Dictionary<string, string> dic, string key, bool isNull = false)
        {
            if (dic.ContainsKey(key.ToLower()))
                return dic[key.ToLower()];
            if (isNull) //可空
                return string.Empty;
            else //不可
                throw new Exception("GetDicByString，字典转换类型失败！");
        }

        /// <summary>
        /// 获取字典里的long类型值
        /// </summary>
        /// <param name="dic">字典</param>
        /// <param name="key">key</param>
        /// <param name="isNull">key的值是否可空，默认不能</param>
        /// <returns></returns>
        public static long GetDicByLong(this Dictionary<string, string> dic, string key, bool isNull = false)
        {
            if (dic.ContainsKey(key.ToLower()) && dic[key.ToLower()] != "")
            {
                return Int64.Parse(dic[key.ToLower()]);
            }
            if (isNull) //可空
                return 0;
            else //不可
                throw new Exception("GetDicByLong，字典转换类型失败！");
        }

        /// <summary>
        /// 获取字典里的decimal类型值
        /// </summary>
        /// <param name="dic">字典</param>
        /// <param name="key">key</param>
        /// <param name="isNull">key的值是否可空，默认不能</param>
        /// <returns></returns>
        public static decimal GetDicByDecimal(this Dictionary<string, string> dic, string key, bool isNull = false)
        {
            if (dic.ContainsKey(key.ToLower()) && dic[key.ToLower()] != "")
                return decimal.Parse(dic[key.ToLower()]);
            if (isNull) //可空
                return 0m;
            else //不可
                throw new Exception("GetDicByDecimal，字典转换类型失败！");
        }

        /// <summary>
        /// 获取字典里的DateTime类型值
        /// </summary>
        /// <param name="dic">字典</param>
        /// <param name="key">key</param>
        /// <param name="isNull">key的值是否可空，默认不能</param>
        /// <returns></returns>
        public static DateTime GetDicByDateTime(this Dictionary<string, string> dic, string key, bool isNull = false)
        {
            if (dic.ContainsKey(key.ToLower()) && dic[key.ToLower()] != "")
                return DateTime.Parse(dic[key.ToLower()]);
            if (isNull) //可空
                return new DateTime().GetMinTime();
            else //不可
                throw new Exception("GetDicByDateTime，字典转换类型失败！");
        }

        /// <summary>
        /// 获取字典里的int类型值
        /// </summary>
        /// <param name="dic">字典</param>
        /// <param name="key">key</param>
        /// <param name="isNull">key的值是否可空，默认不能</param>
        /// <returns></returns>
        public static int GetDicByInt(this Dictionary<string, string> dic, string key, bool isNull = false)
        {
            if (dic.ContainsKey(key.ToLower()) && dic[key.ToLower()] != "")
                return int.Parse(dic[key.ToLower()]);
            if (isNull) //可空
                return 0;
            else //不可
                throw new Exception("GetDicByInt，字典转换类型失败！");
        }
        #endregion
    }
}
